;*****************************************************************************************************
;+
; NAME:
;       IGL_LEGEND
;
; PURPOSE:
;
;       This is a basic vizualisation object which represents a
;       legend panel. It contains single legend items
;       (text+line/symbol) which are implemented as IGL_LegendItem objects.
;
;
; AUTHORS:
;
;        RAPHAEL SADOUN
;        Graduate Student
;        Institut d'Astrophysique de Paris
;        98 bis boulevard Arago
;        75014 PARIS FRANCE
;        E-mail: raphael.sadoun@gmail.com
;
; SUPERCLASSES:
;
;       CATDATAATOM (Catalyst Library)
;
; SYNTAX:
;
;       legend = Obj_New('IGL_Legend')
;
;
; CLASS_STRUCTURE:
;
;       class = {IGL_Legend, $      
;           INHERITS CATDATAATOM, $ ; This is a CATDATAATOM object
;           boxObject:obj_new(), $  ; The polygon object that represents the box around the legend     
;           xpos:0.0, $             ; The upper left starting X location for the legend
;           ypos:0.0, $             ; The upper left starting Y location for the legend
;           vspace:0.0, $           ; The vertical space between legend items
;           hspace:0.0, $           ; The horizontal space between legend items
;           horizontal:0B, $        ; Flag indicating if the legend has an horizontal layout
;           visible:0B $            ; Flag indicating if the legend is visible
;          }
;
;
; MODIFICATION_HISTORY:
;
;       Written by: Raphael Sadoun, 24 April 2012
;-
;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::ADD
;
; PURPOSE:
;
;       This method overrides the default CatAtom::Add method to
;       ensure that only IGL_LegendItem are added to the legend. It
;       also make sure that all added objects share the coordinate
;       system of the legend object and register the legend to receive
;       'OBJECT_DELETED' message from the added objects.
;
; SYNTAX:
;
;       self -> Add, object
;
; ARGUMENTS:
;
;       OBJECT:   The object to add to the legend. Must be a subclass
;                 of IGL_LegendItem.
;
; KEYWORDS:
;
;       _EXTRA:    Any keyword accepted by the superclass ADD method.
;
;-
;*****************************************************************************************************
PRO IGL_Legend::Add, object, _EXTRA=extra

  ;; Get the legend's coordinate system
  self -> GetProperty, Coord_Object=coords

  ;; Make sure we have IGL_LegendItem objects and give them the
  ;; coordinate system of the legend.
  FOR i=0, n_elements(object)-1 DO BEGIN

     IF (obj_isa_valid(object[i],'IGL_LegendItem') EQ 0) THEN message, 'Only Legend Items can be added to a Legend object'
     object[i] -> SetProperty, Coord_Object=coords     
     object[i] -> RegisterForMessage, self, 'OBJECT_DELETED'
     
  ENDFOR

  ;; Add the objects to the legend
  self -> CATDATAATOM::Add, object, _EXTRA=extra

  ;; Report completion
  self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::CALCULATEBOUNDARYBOX
;
; PURPOSE:
;
;       This method calculates the extent of a box which encompasses
;       all the legend items contained in the legend object. It also
;       sets the position of the items according to the current positional
;       properties of the legend.
;
; SYNTAX:
;
;       self -> CalculateBoundaryBox
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       None.
;
;-
;*****************************************************************************************************
PRO IGL_Legend::CalculateBoundaryBox

   @cat_pro_error_handler
   
   ;; Get the starting X and Y location of the legend. They correspond
   ;; to the coordinate of the UPPER LEFT corner.
   xpos = self.xpos
   ypos = self.ypos

   ;; For each legend item, we calculate its position based on the
   ;; height and width of the previous one and on the positional
   ;; parameters of the legend.

   ;; Get all the items
   children = self -> Get(/all,ISA='IGL_LegendItem',count=count)

   ;; Nothing to do if there are no legend items
   IF count EQ 0 THEN RETURN
   
   FOR i=0, count-1 DO BEGIN
      
      ;; The new correct coordinates are available so we assign them
      ;; to the item
      current = children[i] 
      current -> SetProperty, XPOS=xpos, YPOS=ypos
      
      ;; Convert the coordinates to work in normalized units since the
      ;; horizonal and vertical space between items are always in
      ;; normalized units.
      self -> ApplyCoords
      cc = CONVERT_COORD(xpos,ypos,/DATA,/TO_NORMAL)

      ;; Calculate the new coordinates for the next item
      width = current -> GetWidth(/NORMAL)
      height = current -> GetHeight(/NORMAL)
      IF (self.horizontal) THEN BEGIN
         xpos = cc[0]+width+self.hspace
         ypos = cc[1]
      ENDIF ELSE BEGIN
         xpos = cc[0]
         ypos = cc[1]-height-self.vspace
      ENDELSE

      ;; Convert them back to data units
      datapos = CONVERT_COORD(xpos,ypos,/NORMAL,/TO_DATA)
      xpos = datapos[0]
      ypos = datapos[1]

      ;; Calculate the box encompassing the legend item. This assumes
      ;; that the items and the legend share the same coordinate system!!
      x0 = cc[0]
      y0 = cc[1]-0.5*height
      x1 = x0+width
      y1 = y0+height

      ;; Calculate the coordinates of the legend's boundary box
      ;; in normalized units
      IF (n_elements(xmin) EQ 0) THEN xmin = x0 ELSE xmin = xmin < x0
      IF (n_elements(xmax) EQ 0) THEN xmax = x1 ELSE xmax = xmax > x1
      IF (n_elements(ymin) EQ 0) THEN ymin = y0 ELSE ymin = ymin < y0
      IF (n_elements(ymax) EQ 0) THEN ymax = y1 ELSE ymax = ymax > y1
      
   ENDFOR

   ;; Add some padding to the boundary box
   xmin -= 0.015
   xmax += 0.015
   ymin -= 0.015
   ymax += 0.015
   
   ;; Assign the box coordinates to the polygon object. Convert first
   ;; to data units.
   self -> ApplyCoords
   cc = CONVERT_COORD([xmin,xmin,xmax,xmax,xmin],[ymin,ymax,ymax,ymin,ymin],/NORMAL,/TO_DATA)   
   IF (obj_valid(self.boxObject)) THEN self.boxObject -> SetProperty, xpts=cc[0,*], ypts=cc[1,*]

   ;; Report completion
   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::CONTROLPANEL
;
; PURPOSE:
;
;       This method creates a control panel for the graphic.
;
; SYNTAX:
;
;       self -> ControlPanel, baseObject
;
; ARGUMENTS:
;
;       baseObject:    The object reference of a base widget for this control to
;                      be added to. If not supplied, the control panel will be in a
;                      self contained window.
;
; KEYWORDS:
;
;       _EXTRA:       Any keywords appropriate for the CATCONTROLPANEL::INIT method.
;-
;*****************************************************************************************************
PRO IGL_Legend::ControlPanel, baseObject, _EXTRA=extraKeywords

   @cat_pro_error_handler

   ;; Create a new control panel
   cp = OBJ_NEW ('CatControlPanel', self, PARENT=baseObject, COLUMN=1, $
                 TITLE='IGL_Legend Control Panel', _EXTRA=extraKeywords, /No_Cancel, /No_Apply, /No_OK)

   IF (NOT OBJ_VALID (cp)) THEN RETURN

   aproperties = Obj_New('PROPERTYSHEETWIDGET', cp, Value=self, Name='IGL_LEGEND PROPERTYSHEET', YSize=12)
   aproperties -> SetProperty, Event_Object=self

   ;; Display the control panel if it created its own TLB.
   IF cp -> Created_Own_TLB(tlb) THEN tlb -> Draw, /Center

   self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_legend::DRAW
;
; PURPOSE:
;
;       This method draws the graphic in the current display window.
;
; SYNTAX:
;
;       self -> Draw
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       _EXTRA:  Any keyword accepted by the CATATOM and IGL_Polygon
;                draw methods.
;
;-
;*****************************************************************************************************
PRO IGL_Legend::Draw, _EXTRA=extra

  @cat_pro_error_handler
  
  ;; If the legend is invisible, then return immediately.
  IF self.visible EQ 0 THEN RETURN

  ;; Apply the coordinate system.
  self -> ApplyCoords
  
  ;; Calculate the Boundary Box. This will also calculate the position
  ;; of the items.
  self -> CalculateBoundaryBox

  ;; Draw the box.
  IF (obj_valid(self.boxObject)) THEN self.boxObject -> Draw, _EXTRA=extra

  ;; Draw the legend items (children of the Legend object)
  self -> CatAtom::Draw, _EXTRA=extra

  ;; Report completion
  self -> Report, /Completed
   
END

;*****************************************************************************************************
;+
; NAME:
;        IGL_Legend::EVENT_HANDLER
;
; PURPOSE:
;
;        This method is the event handler for the IGL_Legend object. It will typically
;        be used to respond to events from widget objects created in the CONTROLPANEL
;        method.
;
; SYNTAX:
;
;        This method is called automatically by the event handling mechanism.
;
; ARGUMENTS:
;
;       event: The event structure as described in the IDL help files, except
;              that the ID, TOP and HANDLER tags will be object references.
;
; KEYWORDS:
;
;       None.
;
;-
;*****************************************************************************************************
PRO IGL_Legend::EventHandler, event

   @cat_pro_error_handler

   ;; Get the name of the widget generating the event. Branch on this.
   event.ID -> GetProperty, Name=eventName
   
   CASE eventName OF

      'IGL_LEGEND PROPERTYSHEET': BEGIN

         IF event.type EQ 0 THEN BEGIN
            
            CASE StrUpCase(event.identifier) OF

               'BOXCOLOR': BEGIN

                  event.component -> GetProperty, BoxColor=color
                  event.id -> GetProperty, ID=group_leader
                  color = PickColorName(color, Group_Leader=group_leader)
                  event.component -> SetProperty, BoxColor=color

                  ;; Refresh the graphics hierarchy.
                  IGL_RefreshDraw, event.component, /Buffered_Output

               END

               'BGCOLOR': BEGIN

                  event.component -> GetProperty, BGColor=color
                  event.id -> GetProperty, ID=group_leader
                  color = PickColorName(color, Group_Leader=group_leader)
                  event.component -> SetProperty, BGcolor=color

                  ; Refresh the graphics hierarchy.
                  IGL_RefreshDraw, event.component, /Buffered_Output

               END

               ELSE: BEGIN

                  component = event.component
                  identifier = event.identifier
                  event.id -> GetProperty, Value=value, Component=component, Property_Value=identifier
                  event.component -> SetPropertyByIdentifier, identifier, value

                  ;; Refresh the graphics hierarchy.
                  IF OBJ_VALID(event.component) THEN IGL_RefreshDraw, event.component, /Buffered_Output                  

               END

            ENDCASE

         ENDIF ; of BUTTON DOWN EVENT

      END                  

      ;; If you can't handle the event here. Pass it along to superclass EventHandler
      ELSE: self -> CATDATAATOM::EventHandler, event

   ENDCASE

   ;; Report completion
   IF Obj_Valid(self) THEN self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::GETPROPERTY
;
; PURPOSE:
;
;       This method is used to get the object's properties.
;
; SYNTAX:
;
;       self -> GetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     XPOS:        The X location of the legend Upper Left corner.
;
;     YPOS:        The Y location of the legend Upper Left corner.
;
;     DRAWBOX:     Flag indicating if the box is visible.
;
;     BACKGROUND:  Flag indicating if the box background is visible.
;
;     LINESTYLE:   The line style of the box.
;
;     THICKNESS:   The line thickness of the box.
;
;     BOXCOLOR:    The foreground color of the box.
;
;     BGCOLOR:     The background color of the box
;
;     VSPACE:      The vertical space between legend items in
;                  normalized units. The default is 0.02.
;
;     HSPACE:      The horizontal space between legend items in
;                  normalized units. The default is 0.02.
;
;     HORIZONTAL:  Flag indicating if the legend has an horizontal
;                  layout. The default is to layout legend items
;                  vertically.
;
;     VISIBLE:     Flag indicating if the legend is visible.
;
;     BOXOBJECT:   The object reference to the polygon object used as
;                  the box.
;
;     _REF_EXTRA:   Any keywords appropriate for the CATDATAATOM::GetProperty method.
;-
;*****************************************************************************************************
PRO IGL_Legend::GetProperty, DRAWBOX=drawbox, $
                             BACKGROUND=background, $
                             LINESTYLE=linestyle, $
                             THICKNESS=thickness, $
                             BOXCOLOR=boxcolor, $
                             BGCOLOR=bgcolor, $
                             XPOS=xpos, $
                             YPOS=ypos, $
                             VSPACE=vspace, $
                             HSPACE=hspace, $
                             HORIZONTAL=horizontal, $
                             BOXOBJECT=boxobject, $
                             VISIBLE=visible, $
                             DELETE=delete, $
                             _REF_EXTRA=extraKeywords

   @cat_pro_error_handler

   ;; Box properties
   IF (obj_valid(self.boxObject)) THEN BEGIN
      
      self.boxObject -> GetProperty, LINESTYLE=linestyle, $
                                     THICKNESS=thickness, $
                                     PCOLORS=boxcolor, $
                                     VISIBLE=drawbox, $
                                     BACKGROUND=background, $
                                     BG_COLOR=bgcolor      
   ENDIF

   IF (arg_present(xpos)) THEN xpos = self.xpos
   IF (arg_present(ypos)) THEN ypos = self.ypos
   IF (arg_present(vspace)) THEN vspace = self.vspace
   IF (arg_present(hspace)) THEN hspace = self.hspace
   IF (arg_present(horizontal)) THEN horizontal = self.horizontal
   IF (arg_present(visible)) THEN visible = self.visible
   IF (arg_present(boxobject)) THEN boxobject = self.boxObject
   IF (arg_present(delete)) THEN delete = 0 ; Dummy for RegisterProperty functionality

   IF (N_ELEMENTS(extraKeywords) GT 0) THEN self -> CATDATAATOM::GetProperty, _EXTRA=extraKeywords

   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::MESSAGEHANDLER
;
; PURPOSE:
;
;       This method is where messages sent by other objects to this one
;       get treated. It is written primirarly to handle
;       'OBJECT_DELETED' message from children of the target
;       object. It is called automatically when messages are received.
;
; SYNTAX:
;
;       self -> MessageHandler, title
;
; ARGUMENTS:
;
;       TITLE:   The title of the message.
;
; KEYWORDS:
;
;       DATA:    A keyword that contains any information the sender wishes to pass
;                with the message. It can be empty.
;
;       SENDER:  The object that generated the message
;-
;*****************************************************************************************************
PRO IGL_Legend::MessageHandler, title, SENDER=sender, DATA=data

  @cat_pro_error_handler

   CASE title OF

      ;; An OBJECT_DELETED message means the sender is about to be
      ;; destroyed. We need to update the boundary box to reflect this.
      'OBJECT_DELETED': BEGIN

         ;; Turn auto destroy OFF because we don't want the
         ;; object to self destruct just yet.
         sender -> SetProperty, Auto_Destroy=0

         ;; Remove temporarily the object from all its parents
         sender -> GetProperty, parents=parents
         FOR i=0, n_elements(parents)-1 DO BEGIN
            IF OBJ_VALID(parents[i]) THEN parents[i] -> CatAtom::Remove, sender
         ENDFOR

         ;; Refresh graphic hierarchy
         IGL_RefreshDraw, self, /BUFFERED_OUTPUT

         ;; Add back the object as a child of its parents
         FOR i=0, n_elements(parents)-1 DO BEGIN
            sender -> AddParent, parents[i]
         ENDFOR

         ;; Turn auto destroy ON 
         sender -> SetProperty, Auto_Destroy=1
         
      END

      ELSE:

   ENDCASE

   ;; Report completion
   self -> Report, /completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::MOVE
;
; PURPOSE:
;
;       This method moves the legend object in the current window.
;
; SYNTAX:
;
;       self -> Move, x, y
;
; ARGUMENTS:
;
;       X:          The number of pixels to move in the X direction.
;
;       Y:          The number of pixels to move in the Y direction.
;
; KEYWORDS:
;
;       NODRAW:     If this keyword is set, only the coordinates are updated. No drawing occurs.
;
;       PIXMAP:     Set this keyword to a pixmap that can be used to erase the previous
;                   contents of the window.
;-
;*****************************************************************************************************
PRO IGL_Legend::Move, x, y, PIXMAP=pixmap, NODRAW=nodraw

   @cat_pro_error_handler

   ;; Make sure we have a valid coordinate system
   IF OBJ_VALID(self._coords) EQ 0 THEN RETURN

   ;; Convert device pixels to data coordinates
   self._coords -> GetProperty, XRANGE=xr, YRANGE=yr, POSITION=pos
   xx = Abs(xr[1] - xr[0]) / (!D.X_Size * Abs(pos[2]-pos[0])) * x
   yy = Abs(yr[1] - yr[0]) / (!D.Y_Size * Abs(pos[3]-pos[1])) * y

   ;; Add increment to the legend position
   self.xpos += xx
   self.ypos += yy
   
   ;; Need to refresh?
   IF ~Keyword_Set(nodraw) THEN BEGIN

      ;; Redraw, fast if you have a pixmap.
      IF Obj_Isa_Valid(pixmap, 'PIXMAPWIDGET') THEN BEGIN
         self -> CopyParameters, drawID, Destination=d, Extent=e
         pixmap -> Copy, Destination=d, Extent=e, Origin=d
         self -> Draw
      ENDIF ELSE BEGIN
         CatRefreshDraw, self, Stop_At='DRAWWIDGET', /NoErase
      ENDELSE
      
   ENDIF

   ;; Report completion
   self -> Report, /Completed

END



;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::SELECT
;
; PURPOSE:
;
;       This method returns the object reference if the requested point is inside
;       the bounding box of the legend.
;
; SYNTAX:
;
;       object = self -> Select(x,y)
;
; ARGUMENTS:
;
;       X:   The X location of a point in device or window coordinates.
;
;       Y:   The Y location of a point in device or window coordinates.
;
; KEYWORDS:
;
;       SUCCESS:   Set to 1 if a selection is made. To 0 otherwise.
;-
;*****************************************************************************************************
FUNCTION IGL_Legend::Select, x, y, SUCCESS=success

   @cat_func_error_handler

   ;; Set up return values.
   retval = Obj_New()
   success = 0

   ;; No selection is possible if the object is invisible.
   IF self.visible EQ 0 THEN RETURN, retval

   ;; Make sure the box object is valid
   IF OBJ_VALID(self.boxObject) EQ 0 THEN RETURN, retval

   ;; Calculate the Boundary Box
   self -> CalculateBoundaryBox

   ;; Make the box object temporarily visible to be able to select it
   self -> GetProperty, drawbox=boxVisible
   self -> SetProperty, drawbox=1

   ;; Check if the requested location is inside the box
   value = self.boxObject -> Select(x,y,success=success)

   ;; Restore the box visibility state
   self -> SetProperty, drawbox=boxVisible

   ;; If we are inside the box, then the legend is selected
   IF (success) THEN retVal = self

   ;; Report completion
   self -> Report, /Completed
   
   RETURN, retval

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::SETPROPERTY
;
; PURPOSE:
;
;       This method is used to set the object's properties.
;
; SYNTAX:
;
;       self -> SetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     XPOS:        The X location of the legend Upper Left corner.
;
;     YPOS:        The Y location of the legend Upper Left corner.
;
;     DRAWBOX:     Flag indicating if the box is visible.
;
;     BACKGROUND:  Flag indicating if the box background is visible.
;
;     LINESTYLE:   The line style of the box.
;
;     THICKNESS:   The line thickness of the box.
;
;     BOXCOLOR:    The foreground color of the box.
;
;     BGCOLOR:     The background color of the box
;
;     VSPACE:      The vertical space between legend items in
;                  normalized units. The default is 0.02.
;
;     HSPACE:      The horizontal space between legend items in
;                  normalized units. The default is 0.02.
;
;     HORIZONTAL:  Flag indicating if the legend has an horizontal
;                  layout. The default is to layout legend items
;                  vertically.
;
;     VISIBLE:     Flag indicating if the legend is visible.
;
;     DELETE:      Set this keyword to destroy the object.
;
;     _EXTRA:      Any keywords appropriate for the CATDATAATOM::SetProperty method.
;
;-
;*****************************************************************************************************
PRO IGL_Legend::SetProperty, DRAWBOX=drawbox, $
                             BACKGROUND=background, $
                             LINESTYLE=linestyle, $
                             THICKNESS=thickness, $
                             BOXCOLOR=boxcolor, $
                             BGCOLOR=bgcolor, $
                             XPOS=xpos, $
                             YPOS=ypos, $
                             VSPACE=vspace, $
                             HSPACE=hspace, $
                             HORIZONTAL=horizontal, $
                             VISIBLE=visible, $
                             DELETE=delete, $
                             _EXTRA=extraKeywords

   @cat_pro_error_handler

   IF (obj_valid(self.boxObject)) THEN BEGIN

      self.boxObject -> SetProperty, LINESTYLE=linestyle, $
                                     THICKNESS=thickness, $
                                     PCOLORS=boxcolor, $
                                     BG_COLOR=bgcolor, $                                     
                                     background=background, $
                                     visible=drawbox

      IF (n_elements(boxcolor) NE 0) THEN BEGIN
         
         self -> SetPropertyAttribute, 'BOXCOLOR', userdef=CapFirstLetter(boxcolor)
         IF (obj_valid(self._controlPanel)) THEN self._controlPanel -> Refresh_Properties, Properties='BOXCOLOR'
         
      ENDIF

      IF (n_elements(bgcolor) NE 0) THEN BEGIN
         
         self -> SetPropertyAttribute, 'BGCOLOR', userdef=CapFirstLetter(bgcolor)
         IF (obj_valid(self._controlPanel)) THEN self._controlPanel -> Refresh_Properties, Properties='BGCOLOR'
         
      ENDIF
      
   ENDIF

   IF (n_elements(xpos) NE 0) THEN self.xpos = xpos
   IF (n_elements(ypos) NE 0) THEN self.ypos = ypos
   IF (n_elements(hspace) NE 0) THEN self.hspace = 0 > hspace < 1
   IF (n_elements(vspace) NE 0) THEN self.vspace = 0 > vspace < 1
   IF (n_elements(horizontal) NE 0) THEN self.horizontal = keyword_set(horizontal)
   IF (n_elements(visible) NE 0) THEN self.visible = keyword_set(visible)
 
   IF (N_ELEMENTS(extraKeywords) GT 0) THEN self -> CATDATAATOM::SetProperty, _EXTRA=extraKeywords
   
   IF (keyword_set(delete)) THEN BEGIN
      self -> SetProperty, Visible=0
      IGL_RefreshDraw, self, /Buffered_Output
      Obj_Destroy, self._controlPanel
      self -> GetProperty, Parent=parents
      self -> SendMessage, 'OBJECT_DELETED', DATA=self
      FOR j=0,N_Elements(parents)-1 DO parents[j] -> Remove, self
      Obj_Destroy, self
      RETURN
   ENDIF

   IF (obj_valid(self)) THEN self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::CLEANUP
;
; PURPOSE:
;
;       This is the IGL_Legend object class destructor method.
;
; SYNTAX:
;
;       Called automatically when the object is destroyed.
;
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     None.
;-
;*****************************************************************************************************
PRO IGL_Legend::CLEANUP

   @cat_pro_error_handler

   ;; Cleanup the box object
   IF (obj_valid(self.boxObject)) THEN self.boxObject -> RemoveParent, self

   ;; Cleanup the superclass
   self -> CATDATAATOM::CLEANUP

   ;; Report completion
   self -> Report, /Completed
   
END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Legend::INIT
;
; PURPOSE:
;
;       This is the IGL_Legend object class initialization method
;
; SYNTAX:
;
;       Called automatically when the object is created.
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     XPOS:        The X location of the legend Upper Left corner.
;
;     YPOS:        The Y location of the legend Upper Left corner.
;
;     DRAWBOX:     Flag indicating if the box is visible.
;
;     BACKGROUND:  Flag indicating if the box background is visible.
;
;     LINESTYLE:   The line style of the box.
;
;     THICKNESS:   The line thickness of the box.
;
;     BOXCOLOR:    The foreground color of the box.
;
;     BGCOLOR:     The background color of the box
;
;     VSPACE:      The vertical space between legend items in
;                  normalized units. The default is 0.02.
;
;     HSPACE:      The horizontal space between legend items in
;                  normalized units. The default is 0.02.
;
;     HORIZONTAL:  Flag indicating if the legend has an horizontal
;                  layout. The default is to layout legend items vertically.
;
;     _EXTRA:      Any keywords appropriate for the CATDATAATOM::Init method.
;-
;*****************************************************************************************************
FUNCTION IGL_Legend::INIT, XPOS=xpos, $
                           YPOS=ypos, $
                           DRAWBOX=drawbox, $
                           BACKGROUND=background, $
                           LINESTYLE=linestyle, $
                           THICKNESS=thickness, $
                           BOXCOLOR=boxcolor, $
                           BGCOLOR=bgcolor, $
                           VSPACE=vspace, $
                           HSPACE=hspace, $
                           HORIZONTAL=horizontal, $
                           COORD_OBJECT=coord_object, $
                           _Extra=extraKeywords


   @cat_func_error_handler

   ;; Default keyword values
   IF (n_elements(xpos) EQ 0) THEN  xpos = 0.5
   IF (n_elements(ypos) EQ 0) THEN ypos = 0.5
   IF (n_elements(boxcolor) EQ 0) THEN boxcolor = !IGL_P.color
   IF (n_elements(bgcolor) EQ 0) THEN bgcolor = !IGL_P.background
   IF (n_elements(vspace) EQ 0) THEN vspace = 0.02
   IF (n_elements(hspace) EQ 0) THEN hspace = 0.02

   IF OBJ_ISA_VALID(coord_object,'CatCoord') EQ 0 THEN coord_object = obj_new('IGL_Coord',XRANGE=[0,1],YRANGE=[0,1],POSITION=[0,0,1,1])

   ;; Call superclass INIT method
   ok = self -> CATDATAATOM::Init(COORD_OBJECT=coord_object,_Extra=extraKeywords)

   IF (NOT ok) THEN RETURN, 0

   ;; Create the polygon object for the box
   boxObject = obj_new('IGL_Polygon',$
                       COORD_OBJECT=coord_object, $
                       visible=drawbox, $
                       linestyle=linestyle, $
                       thickness=thickness, $
                       color=boxcolor, $
                       bg_color=bgcolor, $
                       background=background)
   boxObject -> AddParent, self

   ;; Load object
   self.boxObject = boxObject
   self.xpos = xpos
   self.ypos = ypos
   self.vspace = 0 > vspace < 1
   self.hspace = 0 > hspace < 1
   self.horizontal = keyword_set(horizontal)
   self.visible = 1

   ;; Change default name and description for the LEGEND object
   self -> SetProperty, name='Legend', description='Legend graphic'

   ;; Set up editable properties
   self -> SetPropertyAttribute, 'NAME', sensitive=0
   self -> SetPropertyAttribute, 'DESCRIPTION', sensitive=0
   self -> RegisterProperty, 'DELETE', /boolean, name='Delete Object'
   self -> RegisterProperty, 'BACKGROUND', /boolean, name='Box Background'
   self -> RegisterProperty, 'BOXCOLOR', 0, name='Box Color (Foreground)', userdef=capFirstLetter(BoxColor)
   self -> RegisterProperty, 'BGCOLOR', 0, name='Box Color (Background)', userdef=capFirstLetter(BGColor)
   self -> RegisterProperty, 'DRAWBOX', /boolean, name='Box Visible'
   self -> RegisterProperty, 'LINESTYLE', /linestyle, name='Box Linestyle'
   self -> RegisterProperty, 'THICKNESS', /integer, valid_range=[1,10], name='Box Thickness'
   self -> RegisterProperty, 'HORIZONTAL', /boolean, name='Horizontal Layout'
   self -> RegisterProperty, 'HSPACE', /float, name='Horizontal Spacing', valid_range=[0,1]
   self -> RegisterProperty, 'VSPACE', /float, name='Vertical Spacing', valid_range=[0,1]

   ;; Report completion
   self -> Report, /Completed

   RETURN, 1

END


;*****************************************************************************************************
;
; NAME:
;       IGL_LEGEND CLASS DEFINITION
;
; PURPOSE:
;
;       This is the IGL_Legend object's structure definition code.
;
;*****************************************************************************************************
PRO IGL_Legend__DEFINE, class

  COMPILE_OPT idl2, HIDDEN

  class = {IGL_Legend, $      
           INHERITS CATDATAATOM, $  ; This is a CATDATAATOM object
           boxObject:obj_new(), $   ; The polygon object that represents the box around the legend     
           xpos:0.0, $              ; The upper left starting X location for the legend
           ypos:0.0, $              ; The upper left starting Y location for the legend
           vspace:0.0, $            ; The vertical space between legend items
           hspace:0.0, $            ; The horizontal space between legend items
           horizontal:0B, $         ; Flag indicating if the legend has an horizontal layout
           visible:0B $             ; Flag indicating if the legend is visible
          }

  struct_hide, class

END
